<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use  App\Models\Course;
use Illuminate\Support\Facades\DB;

/**
 * 视频有效期设置以及视频流输出（用于视频防盗）
 */
class VideoPlayController extends Controller
{
    //刷新过期时间的最低要求，单位分钟(比如视频过期时间小于设置分钟数时，过期时间延长；否则不变动)
    protected static $min_minute = 10;
    //新增的过期时间，单位分钟（重新设置视频多少分钟后过期无法使用）
    protected static $extend_minute = 60;
    //设置可以访问资源的api地址(需要先新建该方法，用于查询实际视频资源)
    protected static $video_api = 'video/videoPlay/play';
    //对应视频资源在表中字段名
    protected $field_name = 'video';
    //对应视频资源在表中字段名
    protected $table = 'heart_recommend';

    public function __construct($table, $field_name)
    {
        parent::__construct();
        $this->table = $table;
        $this->field_name = $field_name;
    }
    /**
     * 播放视频资源接口(用户直接访问播放视频的接口)
     * @param $id int 视频资源id
     * @param 数据对象必须包含过期时间expire_time参数以及视频资源的对应的id
     */
    public function play()
    {
        $id = $this->request->id;
        $rand = $this->request->rand;
        if (empty($rand)) {
            header('HTTP/1.1 500 Internal Server Error');
            echo "Error: Video cannot be played !";
            exit();
        }
        $rand = decrypt($rand, config('other.video_key'));
        if (empty($rand) || $rand < strtotime("-20 min")) {
            header('HTTP/1.1 500 Internal Server Error');
            echo "Error: Video cannot be played !";
            exit();
        }
        $cur_date = date('Y-m-d H:i:s');
        $video = DB::table($this->table)->where('id', $id)->where('expire_time', '>=', $cur_date)->value($this->field_name);
        if (!$video) {
            header('HTTP/1.1 500 Internal Server Error');
            echo "Error: Video cannot be played !";
            exit();
        }
        $video = config('other.img_addr') . $video;
        $this->videoPutStream($video);
    }
    /**
     * 更新过期时间并返回播放接口地址(获取播放地址)
     * @param $obj  obj 要更新数据库的数据对象
     * @param 数据对象必须包含过期时间expire_time参数以及视频资源的对应的id
     * 备注：本项目的expire_time 为datetime格式
     */
    public function getVideoUrl($obj)
    {
        $cur_time = date('Y-m-d H:i:s');
        //如果视频播放时间有效时间只有十分钟之内就延长
        $minute = floor((strtotime($obj->expire_time) - strtotime($cur_time)) % 86400 / 60);
        if ($minute < self::$min_minute) {
            $add_time = self::$extend_minute;
            $expire_time = strtotime($cur_time . "+$add_time minutes");
            $obj->expire_time = date('Y-m-d H:i:s', $expire_time);
            $obj->save();
        }
        //返回播放地址
        $rand = encrypt(time(), config('other.video_key'));
        $video_url = $obj->video = self::$video_api . '?id=' . $obj->id . '&rand=' . $rand;
        return $video_url;
    }
    /**
     * 将视频资源，转为视频流输出
     * @param $videoUrl 视频资源的完整路径地址
     */
    function videoPutStream($videoUrl)
    {
        if (!$videoUrl) {
            header('HTTP/1.1 500 Internal Server Error');
            echo "Error: Video cannot be played !";
            exit();
        }
        //获取视频大小
        $header_array = get_headers($videoUrl, true);
        $sizeTemp = $header_array['Content-Length'];
        if (is_array($sizeTemp)) {
            $size = $sizeTemp[count($sizeTemp) - 1];
        } else {
            $size = $sizeTemp;
        }
        //初始参数
        $start = 0;
        $end = $size - 1;
        $length = $size;
        $buffer = 1024 * 1024 * 10; // 输出的流大小 10m

        //计算 Range
        $ranges_arr = array();
        if (isset($_SERVER['HTTP_RANGE'])) {
            if (!preg_match('/^bytes=\d*-\d*(,\d*-\d*)*$/i', $_SERVER['HTTP_RANGE'])) {
                header('HTTP/1.1 416 Requested Range Not Satisfiable');
            }
            $ranges = explode(',', substr($_SERVER['HTTP_RANGE'], 6));
            foreach ($ranges as $range) {
                $parts = explode('-', $range);
                $ranges_arr[] = array($parts[0], $parts[1]);
            }
            $ranges = $ranges_arr[0];

            $start = (int)$ranges[0];
            if ($ranges[1] != '') {
                $end = (int)$ranges[1];
            }
            $length = min($end - $start + 1, $buffer);
            $end = $start + $length - 1;
        } else {
            // php 文件第一次浏览器请求不会携带 RANGE 为了提升加载速度 默认请求 1 个字节的数据
            $start = 0;
            $end = 1;
            $length = 2;
        }
        //添加 Range 分段请求
        $header = array("Range:bytes={$start}-{$end}");
        #发起请求
        $ch2 = curl_init();
        curl_setopt($ch2, CURLOPT_URL, $videoUrl);
        curl_setopt($ch2, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch2, CURLOPT_HTTPHEADER, $header);
        //设置读取的缓存区大小
        curl_setopt($ch2, CURLOPT_BUFFERSIZE, $buffer);
        // 关闭安全认证
        curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch2, CURLOPT_SSL_VERIFYHOST, false);
        //追踪返回302状态码，继续抓取
        curl_setopt($ch2, CURLOPT_HEADER, false);
        curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch2, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch2, CURLOPT_CONNECTTIMEOUT, 60);
        curl_setopt($ch2, CURLOPT_NOBODY, false);
        curl_setopt($ch2, CURLOPT_REFERER, $videoUrl);
        //模拟来路
        curl_setopt($ch2, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.44");
        $content = curl_exec($ch2);
        curl_close($ch2);
        #设置响应头
        header('HTTP/1.1 206 PARTIAL CONTENT');
        header("Accept-Ranges: bytes");
        header("Connection: keep-alive");
        header("Content-Type: video/mp4");
        header("Access-Control-Allow-Origin: *");
        //为了兼容 ios UC这类浏览器 这里加个判断 UC的 Content-Range 是 起始值-总大小减一
        if ($end != 1) {
            $end = $size - 1;
        }
        header("Content-Range: bytes {$start}-{$end}/{$size}");
        //设置流的实际大小
        header("Content-Length: " . strlen($content));
        //清空缓存区
        ob_clean();

        //输出视频流
        echo  $content;
        die;
        //销毁内存
        unset($content);
    }
}
